const [PENDING, FULFILLED, REJECTED] = ['pending', 'fulfilled', 'rejected']  // 使用常量是为了复用，且编写代码有提示

class APromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    status = PENDING  // 默认状态为等待
    value = undefined // 初始化成功之后的值
    reason = undefined // 初始化失败的原因
    succCallback = [] // 成功回调
    failCallback = [] // 失败回调
    resolve = value => {  // 箭头函数，因为调用该函数时，this 执行应不被改变，指向 Promise 实例
        if(this.status !== PENDING) return  // 如果状态不是等待，则状态不能进行更改
        this.status = FULFILLED // 状态变为成功
        this.value = value // 保存成功之后的值
        // this.succCallback && this.succCallback(this.value)  
        // 如果 succCallback 数组中有内容，则遍历依次执行 succCallback 列表中的成功回调
        while(this.succCallback.length) {
            this.succCallback.shift()()  
            this.failCallback.shift()
        }
    }
    reject = reason => {
        if(this.status !== PENDING) return  // 如果状态不是等待，则状态不能进行更改
        this.status = REJECTED // 状态变为失败
        this.reason = reason // 保存失败的信息
        // this.failCallback && this.failCallback(this.reason) 
        // 如果 failCallback 数组中有内容，则依次执行 failCallback 列表中的失败回调，需要在 reject 中执行
        while(this.failCallback.length) {
            this.failCallback.shift()()
            this.succCallback.shift()
        }
    }
    then (succCallback, failCallback) {
        succCallback = succCallback ? succCallback : value => value;
        failCallback = failCallback ? failCallback : reason => { throw reason };
        let promise2 = new APromise((resolve, reject) => {
            if(this.status === FULFILLED) {
                setTimeout(() => { // 异步执行，为了获取到 promise2
                    try {
                        let succValue = succCallback(this.value)
                        // x 为普通值，则直接调用 resolve 
                        // x 为 promise 对象，则要根据该对象返回的结果决定调用 resolve 还是 reject
                        resolvePromise(promise2, succValue, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            } else if (this.status === REJECTED) {
                setTimeout(() => { // 异步执行，为了获取到 promise2
                    try {
                        let failValue = failCallback(this.reason)
                        resolvePromise(promise2, failValue, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            } else {
                // pending 保存成功和失败回调
                this.succCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let succValue = succCallback(this.value)
                            resolvePromise(promise2, succValue, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
                this.failCallback.push(() => {
                    setTimeout(() => { // 异步执行，为了获取到 promise2
                        try {
                            let failValue = failCallback(this.reason)
                            resolvePromise(promise2, failValue, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
            }
        })
        return promise2
    }
    static all(taskArr) {  // 属于类的静态方法，加 static 关键字
        let results = []
        let totalCount = 0
        return new APromise((resolve, reject) => {
            let addToListByKey = (key, value) => {
                results[key] = value
                totalCount ++
                if(totalCount === taskArr.length) {
                    resolve(results)
                }
            }
            for (let i = 0; i < taskArr.length; i++) {
                let currentTask = taskArr[i];
                if(currentTask instanceof APromise) {
                    // promise 对象
                    currentTask.then(value => {
                        addToListByKey(i, value)
                    }, reason => {
                        reject(reason)  // 有任何一个任务失败则直接调用失败回调
                    })
                } else {
                    // 普通值
                    addToListByKey(i, currentTask)
                }
            }
            // resolve(results)
        })
    }
    static resolve(value) {
        if(value instanceof APromise) {
            // promise 对象，则直接返回
            return value
        } else {
            // 普通值
            return new APromise((resolve, reject) => {
                resolve(value)
            })
        }
    }
    finally (callback) {
       return this.then(value => {
           return APromise.resolve(callback()).then(() => value)
       }, reason => {
           return APromise.resolve(callback()).then(() => { throw reason })
       })
    }
    catch (errCallback) {
        return this.then(undefined, errCallback)
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    if(promise2 === x) {
        return reject(new TypeError('Chaining cycle in promise'))
    }
    if(x instanceof APromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

module.exports = APromise